<template><div><h2 id="验证码" tabindex="-1"><a class="header-anchor" href="#验证码"><span>验证码</span></a></h2>
<p>验证码，英文单词为 <strong>CAPTCHA</strong>，它是 <strong>C</strong>ompletely <strong>A</strong>utomated <strong>P</strong>ublic <strong>T</strong>uring test to tell <strong>C</strong>omputers and <strong>H</strong>umans <strong>A</strong>part 的英文缩写，中文翻译为: <strong>全自动区分计算机和人类的公开图灵测试</strong>，是一种区分用户是机器或人类的公共全自动程序。</p>
<p>在 CAPTCHA 测试中，作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判，但是必须只有人类才能解答。由于机器无法解答 CAPTCHA 的问题，回答出问题的用户即可视为人类。</p>
<p>Yii2 的基础应用模板和高级应用模板都提供了简单的，开箱即用的图形验证码的示例代码。</p>
<h2 id="基本流程" tabindex="-1"><a class="header-anchor" href="#基本流程"><span>基本流程</span></a></h2>
<p>使用 Yii2 的验证码，一般包括以下步骤：</p>
<ol>
<li>覆盖 <code v-pre>\yii\web\Controller::actions()</code> 方法，然后用 ID ‘captcha’ 注册 <code v-pre>yii\captcha\CaptchaAction</code> 类的一个动作；</li>
<li>在表单模型中，声明一个属性来存储用户输入的验证代码，并声明由 ‘captcha’ 验证器验证的属性；</li>
<li>在控制器视图中，在表单中插入一个 <code v-pre>yii\captcha\Captcha</code> 小部件。</li>
</ol>
<blockquote>
<p>注意：验证码包中的 <code v-pre>yii\captcha\CaptchaAction</code> 需要 GD2 或 ImageMagick 的 PHP 扩展。</p>
</blockquote>
<h2 id="captcha-动作" tabindex="-1"><a class="header-anchor" href="#captcha-动作"><span>Captcha 动作</span></a></h2>
<p><code v-pre>yii\captcha\CaptchaAction</code> 负责渲染一个 CAPTCHA 图像。它一般与 <code v-pre>yii\captcha\Captcha</code> 和 <code v-pre>yii\Captcha\CaptchaValidator</code> 一起使用来提供验证码功能。</p>
<p>通过配置 <code v-pre>yii\captcha\CaptchaAction</code> 的属性，您可以定制生成的 CAPTCHA 图像的外观，例如字体颜色、背景颜色等。</p>
<p>在高级应用模板中的 <code v-pre>frontend</code> 应用中的 <code v-pre>SiteController</code> 控制器中的 <code v-pre>actions()</code> 方法中，代码如下：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">frontend<span class="token punctuation">\</span>controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Yii</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>web<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">SiteController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * <span class="token punctuation">{</span><span class="token keyword">@inheritdoc</span><span class="token punctuation">}</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">actions</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'captcha'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\captcha\CaptchaAction'</span><span class="token punctuation">,</span></span>
<span class="line"></span>
<span class="line">                <span class="token string single-quoted-string">'fixedVerifyCode'</span> <span class="token operator">=></span> <span class="token constant">YII_ENV_TEST</span> <span class="token operator">?</span> <span class="token string single-quoted-string">'testme'</span> <span class="token punctuation">:</span> <span class="token constant">null</span><span class="token punctuation">,</span> <span class="token comment">//测试时开启的固定验证码</span></span>
<span class="line">                <span class="token string single-quoted-string">'testLimit'</span> <span class="token operator">=></span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token comment">//相同验证码应显示次数，小于或等于0的值表示测试是无限的</span></span>
<span class="line"></span>
<span class="line">                <span class="token string single-quoted-string">'width'</span> <span class="token operator">=></span> <span class="token number">120</span><span class="token punctuation">,</span> <span class="token comment">//宽度</span></span>
<span class="line">                <span class="token string single-quoted-string">'height'</span> <span class="token operator">=></span> <span class="token number">50</span><span class="token punctuation">,</span> <span class="token comment">//高度</span></span>
<span class="line">                <span class="token string single-quoted-string">'padding'</span> <span class="token operator">=></span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token comment">//间距</span></span>
<span class="line">                <span class="token string single-quoted-string">'backColor'</span> <span class="token operator">=></span> <span class="token number">0xFFFFFF</span><span class="token punctuation">,</span> <span class="token comment">//背景色</span></span>
<span class="line">                <span class="token string single-quoted-string">'foreColor'</span> <span class="token operator">=></span> <span class="token number">0x2040A0</span><span class="token punctuation">,</span> <span class="token comment">//字色</span></span>
<span class="line">                <span class="token string single-quoted-string">'transparent'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span> <span class="token comment">//是否使用透明背景</span></span>
<span class="line">                <span class="token string single-quoted-string">'maxLength'</span> <span class="token operator">=></span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token comment">//随机生成的验证码字最大长度</span></span>
<span class="line">                <span class="token string single-quoted-string">'minLength'</span> <span class="token operator">=></span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token comment">//随机生成的验证码字最小长度</span></span>
<span class="line">                <span class="token string single-quoted-string">'offset'</span> <span class="token operator">=></span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token comment">//字符之间的偏移量</span></span>
<span class="line">                <span class="token string single-quoted-string">'fontFile'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'@yii/captcha/SpicyRice.ttf'</span><span class="token punctuation">,</span> <span class="token comment">//设置字体文件</span></span>
<span class="line">                <span class="token comment">//'imageLibrary' => 'gd', //要使用的渲染库，目前只支持'gd'和'imagick'</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>问你可以方法应用模板的示例 Contact 页面，效果如下：</p>
<p><img src="https://cdn.learnku.com/uploads/images/202202/28/93088/YvJGJgBpLq.png!large" alt="Contact 页面"></p>
<p>如图所示，我们可以看到在控制器设置的验证码，已经出现在页面上，具体如何在前端渲染出来的，我们接着看下一节。</p>
<h2 id="captcha-小部件" tabindex="-1"><a class="header-anchor" href="#captcha-小部件"><span>Captcha 小部件</span></a></h2>
<p><code v-pre>yii\captcha\Captcha</code> 类呈现一个 CAPTCHA 图像和一个输入字段，该字段接受用户输入的验证码。它一般被用于与 <code v-pre>yii\captcha\CaptchaAction</code> 一起工作，来提供 <a href="https://zh.wikipedia.org/wiki/%E9%AA%8C%E8%AF%81%E7%A0%81" target="_blank" rel="noopener noreferrer">CAPTCHA</a>，可以有效防止网站垃圾邮件注册。</p>
<p>由 <code v-pre>yii\captcha\Captcha</code> 渲染的图像元素（<img />）将显示一个 Captcha 图像，它是由 <code v-pre>captchaAction</code> 指定的路由动作生成的。该动作必须是 <code v-pre>yii\captcha\CaptchaAction</code> 的实例。</p>
<p>您可以这样使用这个带有 model 属性的验证码小部件，具体代码如下：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">echo</span> <span class="token class-name static-context">Captcha</span><span class="token operator">::</span><span class="token function">widget</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'model'</span> <span class="token operator">=></span> <span class="token variable">$model</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'attribute'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'captcha'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>您也可以使用 name 属性来做代替方案，具体如下：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">echo</span> <span class="token class-name static-context">Captcha</span><span class="token operator">::</span><span class="token function">widget</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'captcha'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也可以在 <code v-pre>yii\widgets\ActiveForm</code> 中使用 <code v-pre>yii\widgets\ActiveField::widget()</code> 方法，来使用这个验证码小部件，就像上一节中的 contact 视图页面中，具体示例如下：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">use yii\captcha\Captcha;</span>
<span class="line"></span>
<span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?=</span> <span class="token variable">$form</span><span class="token operator">-></span><span class="token function">field</span><span class="token punctuation">(</span><span class="token variable">$model</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'verifyCode'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">widget</span><span class="token punctuation">(</span><span class="token class-name static-context">Captcha</span><span class="token operator">::</span><span class="token function">className</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'template'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'&lt;div class="row">&lt;div class="col-lg-3">{image}&lt;/div>&lt;div class="col-lg-6">{input}&lt;/div>&lt;/div>'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token delimiter important">?></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当用户点击这个 CAPTCHA 图像时，它将导致这个 CAPTCHA 图像被一个新的 CAPTCHA 刷新。</p>
<h2 id="captcha-验证器" tabindex="-1"><a class="header-anchor" href="#captcha-验证器"><span>Captcha 验证器</span></a></h2>
<p><code v-pre>\yii\captcha\CaptchaValidator</code> 验证器，负责验证属性值是否与 CAPTCHA 中显示的验证码相同。它一般要与 <code v-pre>\yii\captcha\CaptchaAction</code> 搭配一起使用。</p>
<p>在应用模板示例代码中，我们可以看到 Captcha 验证器的使用，具体如下：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">frontend<span class="token punctuation">\</span>models</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Yii</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>base<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ContactForm</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$verifyCode</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * <span class="token punctuation">{</span><span class="token keyword">@inheritdoc</span><span class="token punctuation">}</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">rules</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token comment">// verifyCode 需要正确输入</span></span>
<span class="line">            <span class="token punctuation">[</span><span class="token string single-quoted-string">'verifyCode'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'captcha'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'message'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'验证码错误'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * <span class="token punctuation">{</span><span class="token keyword">@inheritdoc</span><span class="token punctuation">}</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">attributeLabels</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">           <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'verifyCode'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'验证码'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>注意：一旦 CAPTCHA 验证成功，一个新的 CAPTCHA 将自动生成。因此，CAPTCHA 验证不应该在 AJAX 验证模式中使用，因为即使用户输入了与 CAPTCHA 图像中显示的相同的代码（实际上与最新的CAPTCHA代码不同），验证也可能失败。</p>
</blockquote>
<blockquote>
<p>💖喜欢本文档的，欢迎点赞、收藏、留言或转发，谢谢支持！<br>
作者邮箱：zhuzixian520@126.com，github地址：<a href="https://github.com/zhuzixian520" target="_blank" rel="noopener noreferrer">github.com/zhuzixian520</a></p>
</blockquote>
</div></template>


